package com.tbit.uqbike.client.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tbit.uqbike.client.constant.*;
import com.tbit.uqbike.client.dao.core.ColorCodeDao;
import com.tbit.uqbike.client.dao.core.MachineFunctionDao;
import com.tbit.uqbike.client.dao.core.ParkPointBoundDao;
import com.tbit.uqbike.client.dao.log.PhotoUploadLogDao;
import com.tbit.uqbike.client.pojo.*;
import com.tbit.uqbike.client.pojo.newEntity.*;
import com.tbit.uqbike.client.service.*;
import com.tbit.uqbike.client.util.GeoUtil;
import com.tbit.uqbike.client.util.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Author: chen
 * @Description:
 * @Date: 创建于 9:33 2021/7/8
 */
@Service
@Slf4j
public class MachineCheckServiceImpl implements MachineCheckService {

    @Autowired
    private CacheService cacheService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ParkPointBoundDao parkPointBoundDao;
    @Autowired
    private ParkPointService parkPointService;
    @Autowired
    private MachineFunctionDao machineFunctionDao;
    @Autowired
    private MachineService machineService;
    @Autowired
    private PhotoUploadLogDao photoUploadLogDao;
    @Autowired
    private ColorCodeDao colorCodeDao;
    @Autowired
    private MachineBorrowService machineBorrowService;

    /**
     * rfid uid转化
     *
     * @param uid rfid uid
     * @return 转化后的编号
     */
    public static String getUid(String uid) {
        String[] strings = uid.split(":");
        List<String> list = new ArrayList<>();
        for (String s : strings) {
            list.add(0, s);
        }
        StringBuffer stringBuffer = new StringBuffer();
        list.forEach(s -> stringBuffer.append(s));
        return stringBuffer.toString();
    }

    /**
     * 校验还车次数是否满足还车条件
     *
     * @param accountKey 区域key
     * @param redisKey   缓存key
     * @param dispatch   调度信息
     * @param machineNO  设备编号
     * @param accountId  区域id
     * @return 调度信息
     */
    private Dispatch checkReturnNum(String accountKey, String redisKey, Dispatch dispatch, String machineNO, Integer accountId) {
        /*系统配置的次数*/
        Integer systemNum = Integer.valueOf(Optional.ofNullable(cacheService.getAccountConfigExtByKey(accountId
                , accountKey)).map(AccountConfigExt::getParamValue).orElse("0"));
        /*已经还车的次数*/
        Integer returnNum = Integer.valueOf(Optional.ofNullable(redisService.get(redisKey + machineNO)).orElse("0"));
        if (returnNum >= systemNum && systemNum > 0) {
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }

        return dispatch;
    }

    @Override
    public Dispatch checkWebcam(Integer accountId, String machineNO, Integer parkPointId, String tlvs, Integer isLast) {
        log.info("摄像头检测1,accountId={},machineNO={},parkPointId={},tlvs={}", accountId, machineNO, parkPointId, tlvs);
        Dispatch dispatch = new Dispatch(DisPatchConstant.DISPATCH_SXT, null);
        /**站点有开启摄像头功能*/
        ParkFeature parkFeature = cacheService.getParkFeature(parkPointId, ParkFeatureConstant.PARKFEATURE_TYPE_SXT);
        if (parkFeature == null || parkFeature.getEnable() != 1) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        AccountConfigExt configExt = cacheService.getAccountConfigExtByKey(accountId,
                AccountConfigExtConstant.ACCOUNTCONFIG_SXT);
        if (configExt == null) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        String value = configExt.getParamValue();
        String button;
        String angle = "";
        /**有设置角度*/
        if (value.contains(",")) {
            button = value.split(",")[0];
            angle = value.split(",")[1];
        } else {
            button = value;
        }
        log.info("摄像头检测2,configExt={},button={},angle={}", JSON.toJSONString(configExt), button, angle);
        /**兼容辅助还车功能需要站点跟设备都支持功能才行*/
        boolean state = machineFunctionCheck(machineNO, MachineStateConstant.MACHINE_TYPE_WEBCAM);
    /*if(!state){
      return new Dispatch(DisPatchConstant.DISPATCH_PARK,null);
    }*/
        /**兼容T摄像头跟普通摄像头同样判断逻辑*/
        boolean state1 = machineFunctionCheck(machineNO, MachineStateConstant.MACHINE_TYPE_T_SXT);
        if (!state1 && !state) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        if (!"1".equals(button)) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        String json = redisService.get(FunctionConstant.WEBCAM + machineNO);

        if (tlvs != null) {
            json = tlvs;
        }
        if (json != null) {
            Integer times = 3;
            WebcamInfo webcamInfo = JSON.parseObject(json, WebcamInfo.class);
            Integer sbAngle = webcamInfo.getPicDir().intValue();
            String webcamNum = redisService.get(RedisConstant.WEBCAM_FAIL_KEY_PREFIX + machineNO);
            if (webcamNum == null) {
                webcamNum = "0";
            }


            /**返回结果为未检测到摄像头、终端不支持ai摄像头、摄像头未通信成功，可直接还车*/
            if ((webcamInfo.getRet() == GatewayProtocol.RSP_RESULT_STATUS9 || webcamInfo.getRet() == GatewayProtocol.RSP_RESULT_STATUS8)
                    && Integer.valueOf(webcamNum) > times) {
                return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
            }
            if (isLast == 1) {
                /**缓存还车角度判断次数*/
                redisService.add(RedisConstant.WEBCAM_FAIL_KEY_PREFIX + machineNO,
                        String.valueOf(Integer.valueOf(webcamNum) + 1), 300);
            }

            /**返回结果成功，角度在合法值*/
            if (webcamInfo.getRet() == GatewayProtocol.RSP_RESULT_SUCCESS && ("".equals(angle) || sbAngle <= Integer.valueOf(angle))) {
                return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
            }
            /**兼容用户还车次数达到一定次数直接可以还车*/
            dispatch=checkReturnNum(AccountConfigExtConstant.ACCOUNTCONFIG_SXT_NUM,RedisConstant.WEBCAM_FAIL_KEY_PREFIX,dispatch,machineNO,accountId);

        }
        log.info("摄像头检测6,dispatch={}", JSON.toJSONString(dispatch));

        return dispatch;
    }

    @Override
    public Dispatch checkRfid(Integer accountId, String machineNO, Integer parkPointId, String tlvs, Integer isLast) {
        Dispatch dispatch = new Dispatch(DisPatchConstant.DISPATCH_RFID, null);
        /**站点有开启rfid功能*/
        ParkFeature parkFeature = cacheService.getParkFeature(parkPointId, ParkFeatureConstant.PARKFEATURE_TYPE_RFID);
        if (parkFeature == null || parkFeature.getEnable() != 1) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        AccountConfigExt configExt = cacheService.getAccountConfigExtByKey(accountId,
                AccountConfigExtConstant.ACCOUNTCONFIG_RFID);
        if (configExt == null) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        String button = configExt.getParamValue();
        String[] strings = button.split(",");
        if (!"1".equals(strings[0])) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        /**兼容辅助还车功能需要站点跟设备都支持功能才行*/
        boolean state = machineFunctionCheck(machineNO, MachineStateConstant.MACHINE_TYPE_RFID);
        if (!state) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        String value = redisService.get(FunctionConstant.RFID + machineNO);
        /**兼容数据主动传递*/
        if (tlvs != null) {
            value = tlvs;
        }

        if (value != null) {
            JSONObject jsonObject = JSON.parseObject(value);
            Integer ret = jsonObject.getInteger("ret");
            Integer times = 3;
            if (strings.length >= 2) {
                times = Integer.valueOf(strings[1]);
            }
            String rfidNum = redisService
                    .get(RedisConstant.RFID_FAIL_KEY_PREFIX + machineNO);
            if (rfidNum == null) {
                rfidNum = "0";
            }
            if (ret == GatewayProtocol.RSP_RESULT_STATUS13 && Integer.valueOf(rfidNum) >= times) {
                return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
            }
            if (isLast == 1) {
                /**缓存还车角度判断次数*/
                redisService.add(RedisConstant.RFID_FAIL_KEY_PREFIX + machineNO,
                        String.valueOf(Integer.valueOf(rfidNum) + 1), 300);
            }

            /**终端不支持该RFID读卡器型号、通信超时、成功 都认为可以还车*/
            if (ret != null && (ret == GatewayProtocol.RSP_RESULT_STATUS12 || ret == GatewayProtocol.RSP_RESULT_SUCCESS)) {
                return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
            }
            /**兼容用户还车次数达到一定次数直接可以还车*/
            dispatch=checkReturnNum(AccountConfigExtConstant.ACCOUNTCONFIG_RFID_NUM,RedisConstant.RFID_FAIL_KEY_PREFIX,dispatch,machineNO,accountId);

        }
        return dispatch;
    }

    @Override
    public Integer isInRfid(String value, Integer accountId, String machineNO, Point point) {
        Integer parkPointId = null;
        JSONObject jsonObject = JSON.parseObject(value);
        if (!"1".equals(jsonObject.getString("ret"))) {
            return null;
        }
        String UID = getUid(jsonObject.getString("UID"));

        redisService.add(RedisConstant.MACHINE_RFID + machineNO, jsonObject.getString("UID"), 600);
        ParkPointBound parkPointBoundDB = parkPointBoundDao.getByNO(UID);
        if (parkPointBoundDB != null) {
            /**更新最后时间*/
            ParkPointBound parkPointBound = new ParkPointBound();
            parkPointBound.setMachineNO(UID);
            parkPointBound.setUpdateTime(new Date());
            parkPointBoundDao.edit(parkPointBound);
            /**检验距离有效性,车辆位置跟站点距离不能超出设定的值才认为有效*/
            ParkPoint parkPoint = parkPointService.getByParkPointId(parkPointBoundDB.getParkPointId());
            if (parkPoint != null) {
                List<Point> points = GeoUtil.getPoints(parkPoint.getPoints());
                /**判断是否在多边形内*/
                if (GeoUtil.IsPtInPoly(point, points)) {
                    parkPointId = parkPoint.getParkPointId();
                } else {
                    Double distince = GeoUtil.getDistance(point, points);
                    /**默认200米*/
                    Integer allowRange = 200;
                    AccountConfigExt configExt = cacheService.getAccountConfigExtByKey(accountId,
                            AccountConfigExtConstant.ACCOUNTCONFIG_RFID_RETURN_ALLOWRANGE);
                    if (configExt != null) {
                        allowRange = Integer.valueOf(configExt.getParamValue());
                    }

                    if (distince <= allowRange) {
                        parkPointId = parkPoint.getParkPointId();
                    } else {
                        log.info(machineNO + "还车判断位置站点过远" + distince);
                    }
                }
            }
        }
        /**兼容还车是否校验uid跟站点id绑定关系,1代表打开开关，0代表关闭*/
        AccountConfigExt rfidconfig = cacheService.getAccountConfigExtByKey(accountId,
                AccountConfigExtConstant.ACCOUNTCONFIG_RFID_PARK_BOUND);
        if (rfidconfig != null && "1".equals(rfidconfig.getParamValue()) && parkPointId == null) {
            parkPointId = -3;
        }

        return parkPointId;
    }

    @Override
    public Dispatch checkCdz(Integer accountId, String machineNO, Integer parkPointId, String orderNO, Integer isLast) {
        Dispatch dispatch = new Dispatch(DisPatchConstant.DISPATCH_CDZ, null);
        /**站点有开启充电桩功能*/
        ParkFeature parkFeature = cacheService.getParkFeature(parkPointId, ParkFeatureConstant.PARKFEATURE_TYPE_CDZ);
        if (parkFeature == null || parkFeature.getEnable() != 1) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        AccountConfigExt configExt = cacheService.getAccountConfigExtByKey(accountId,
                AccountConfigExtConstant.ACCOUNTCONFIG_CDZ);
        if (configExt == null || "0".equalsIgnoreCase(configExt.getParamValue())) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        /**兼容辅助还车功能需要站点跟设备都支持功能才行*/
        boolean state = machineFunctionCheck(machineNO, MachineStateConstant.MACHINE_TYPE_CDZ);
        if (!state) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        String value = redisService.get(FunctionConstant.RFID + machineNO);
        if (value != null) {
            JSONObject jsonObject = JSON.parseObject(value);
            Integer ret = jsonObject.getInteger("ret");
            /**记录校验结果*/
            Boolean result = false;
            if (ret == GatewayProtocol.RSP_RESULT_SUCCESS) {
                result = true;
            }
            LogUtil.info("充电桩设备编号=" + machineNO + ",订单编号=" + orderNO + "parkPointId=" + parkPointId + "ret=" + ret + "结果=" + result);
            /**终端不支持该RFID读卡器型号、通信超时、成功 都认为可以还车*/
            if (ret != null && ret == GatewayProtocol.RSP_RESULT_SUCCESS) {
                return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
            }
            String num =Optional.ofNullable(redisService.get(RedisConstant.CDZ_FAIL_KEY_PREFIX+machineNO)).orElse("0");
            if (isLast == 1) {
                /**缓存还车角度判断次数*/
                redisService.add(RedisConstant.CDZ_FAIL_KEY_PREFIX + machineNO,
                        String.valueOf(Integer.valueOf(num) + 1), 300);
            }
            /**兼容用户还车次数达到一定次数直接可以还车*/
            dispatch=checkReturnNum(AccountConfigExtConstant.ACCOUNTCONFIG_CDZ_NUM,RedisConstant.CDZ_FAIL_KEY_PREFIX,dispatch,machineNO,accountId);

        }

        return dispatch;
    }

    @Override
    public Dispatch checkJc(Integer accountId, String machineNO, Integer parkPointId,
                            String orderNO, Integer isLast) {
        Dispatch dispatch = new Dispatch(DisPatchConstant.DISPATCH_JC, null);
        /**站点有开启rfid功能*/
        ParkFeature parkFeature = cacheService.getParkFeature(parkPointId, ParkFeatureConstant.PARKFEATURE_TYPE_JC);
        if (parkFeature == null || parkFeature.getEnable() != 1) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        /**兼容辅助还车功能需要站点跟设备都支持功能才行*/
        boolean state = machineFunctionCheck(machineNO, MachineStateConstant.MACHINE_TYPE_JC);
        if (!state) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        String value = redisService.get(FunctionConstant.RFID + machineNO);
        if (value != null) {
            JSONObject jsonObject = JSON.parseObject(value);
            Integer ret = jsonObject.getInteger("ret");
            /**记录校验结果*/
            Boolean result = false;
            if (ret == GatewayProtocol.RSP_RESULT_SUCCESS) {
                result = true;
            }
            LogUtil.info("脚撑设备编号=" + machineNO + ",订单编号=" + orderNO + "parkPointId=" + parkPointId + "ret=" + ret + "结果=" + result);
            /**终端不支持该RFID读卡器型号、通信超时、成功 都认为可以还车*/
            if (ret != null && ret == GatewayProtocol.RSP_RESULT_SUCCESS) {
                return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
            }

            String num =Optional.ofNullable(redisService.get(RedisConstant.JC_FAIL_KEY_PREFIX+machineNO)).orElse("0");
            if (isLast == 1) {
                /**缓存还车角度判断次数*/
                redisService.add(RedisConstant.JC_FAIL_KEY_PREFIX + machineNO,
                        String.valueOf(Integer.valueOf(num) + 1), 300);
            }
            /**兼容用户还车次数达到一定次数直接可以还车*/
            dispatch=checkReturnNum(AccountConfigExtConstant.ACCOUNTCONFIG_JC_NUM,RedisConstant.JC_FAIL_KEY_PREFIX,dispatch,machineNO,accountId);

        }

        return dispatch;
    }

    @Override
    public Dispatch checkPhonePhoto(Integer accountId, Machine machine, Integer parkPointId, String orderNO, Integer isLast,
                                    Integer userId, RideLog rideLog) {
        Dispatch dispatch = new Dispatch(DisPatchConstant.DISPATCH_PHONE, null);
        AccountConfigExt configExt = cacheService.getAccountConfigExtByKey(machine.getAccountId(),
                AccountConfigExtConstant.ACCOUNTCONFIG_PHONE);
        if (configExt == null || "0".equalsIgnoreCase(configExt.getParamValue())) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        /**站点是否开启功能*/
        ParkFeature parkFeature = cacheService.getParkFeature(parkPointId, ParkFeatureConstant.PARKFEATURE_TYPE_PHONE);
        if (parkFeature == null || parkFeature.getEnable() != 1) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        /**兼容辅助还车功能需要站点跟设备都支持功能才行*/
        boolean state = machineFunctionCheck(machine.getMachineNO(), MachineStateConstant.PHOTO_RETURN_CAR);
        if (!state) {
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        /**兼容每日免费骑行不需要拍照*/
        boolean isPhoto = machineService.checkIsPhoto(userId, rideLog, machine);
        if (!isPhoto) {
            log.info("每日免费骑行不需要拍照,machineNo{},orderNo{},userId{}", machine.getMachineNO(),orderNO,userId);
            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        }
        /**校验车辆是否绑定颜色码*/
//        ColorCode colorCode = colorCodeDao.getByMachineId(machine.getMachineId());
//        if (colorCode == null) {
//            return new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
//        }
        String result = redisService.get(RedisConstant.PHONE_PHOTO_RESULT + orderNO);
        /**是否有上传图片*/
        PhotoUploadLog photoUploadLog = photoUploadLogDao.getByOrderNO(orderNO);
        if (photoUploadLog == null) {
            return dispatch;
        }
        dispatch = checkPhotoResult(photoUploadLog, result);
        /**缓存还车角度判断次数*/
        Integer returnNum = photoUploadLogDao.getCount(orderNO);
        redisService.add(RedisConstant.PHONE_FAIL_KEY_PREFIX + machine.getMachineNO(),
                String.valueOf(returnNum), 300);

        /**兼容用户还车次数达到一定次数直接可以还车*/
        dispatch=checkReturnNum(AccountConfigExtConstant.ACCOUNTCONFIG_PHONE_NUM,RedisConstant.PHONE_FAIL_KEY_PREFIX,dispatch,machine.getMachineNO(),accountId);

        photoUploadLog.setParkPointId(parkPointId);
        photoUploadLogDao.edit(photoUploadLog);
        return dispatch;
    }

    /**
     * 校验结果
     *
     * @param photoUploadLog 拍照记录
     * @param result 结果
     * @return
     */
    public Dispatch checkPhotoResult(PhotoUploadLog photoUploadLog, String result) {
        Dispatch dispatch;
        photoUploadLog.setResult(0);
        JSONObject jsonObject = JSON.parseObject(Optional.ofNullable(result).orElse("{}"));
        if (jsonObject.isEmpty()) {
            photoUploadLog.setResult(1);
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        } else if ("200".equalsIgnoreCase(jsonObject.getString("code"))) {
            /**1成功、0失败 暂时直接通过，后续需要校验*/
            photoUploadLog.setResult(1);
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PARK, null);
        } else if ("1001".equalsIgnoreCase(jsonObject.getString("code"))) {
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PHONE_ANGLE, null);
        } else if ("1002".equalsIgnoreCase(jsonObject.getString("code"))) {
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PHONE_DISTANCE, null);
        } else if ("1101".equalsIgnoreCase(jsonObject.getString("code"))) {
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PHONE_OPPOSITE, null);
        } else if ("90002".equalsIgnoreCase(jsonObject.getString("code"))) {
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PEDAL_COLOR_ERROR, null);
        } else if ("90003".equalsIgnoreCase(jsonObject.getString("code"))) {
            dispatch = new Dispatch(DisPatchConstant.BICYCLE_SEAT_CUSHION_ERROR, null);
        } else if ("90004".equalsIgnoreCase(jsonObject.getString("code"))) {
            dispatch = new Dispatch(DisPatchConstant.MACHINE_LICENSE_PLATE, null);
        } else if ("90005".equalsIgnoreCase(jsonObject.getString("code"))) {
            dispatch = new Dispatch(DisPatchConstant.PEDAL_ERROR, null);
        } else {
            dispatch = new Dispatch(DisPatchConstant.DISPATCH_PHONE_ERROR, null);
        }
        return dispatch;
    }

    /**
     * 检测设备是否支持功能
     *
     * @param machineNO
     * @param type
     * @return
     */
    public boolean machineFunctionCheck(String machineNO, Integer type) {
        Machine machine = machineService.getByMachineNO(machineNO);
        Map<String, Object> param = new HashMap<>();
        param.put("machineId", machine.getMachineId());
        param.put("functionType", type);
        MachineFunction machineFunction = machineFunctionDao.getByMachineId(param);
        if (machineFunction == null || machineFunction.getFunctionValue() != 1) {
            return false;
        }
        return true;
    }

}
